package com.hmall.item.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmall.common.dto.PageDTO;
import com.hmall.common.dto.SearchParams;
import com.hmall.common.dto.SearchVo;
import com.hmall.item.mapper.ItemMapper;
import com.hmall.item.pojo.Item;
import com.hmall.item.pojo.ItemDoc;
import com.hmall.item.service.IItemService;
import com.hmall.utils.UserThreadLocal;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.lucene.search.function.CombineFunction;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;

@Service
public class ItemService extends ServiceImpl<ItemMapper, Item> implements IItemService {
    @Autowired
    private ItemMapper itemMapper;
    @Override
    public PageDTO getPage(Integer page, Integer size) {
        IPage page1=new Page<>(page,size);
        IPage itemIPage = itemMapper.selectPage(page1, null);
        PageDTO<Item> pageDto=new PageDTO();
        pageDto.setTotal(itemIPage.getTotal());
        pageDto.setList(itemIPage.getRecords());
        return pageDto;
    }

    @Override
    public void insert(Item item) {
        item.setCreateTime(LocalDateTime.now());
        System.out.println(UserThreadLocal.getSubject());
        itemMapper.insert(item);
    }

    @Override
    public void updateStatus(Long id, Integer status) {
        itemMapper.updateStatus(id,status);
    }

    @Override
    public SearchVo fliters(SearchParams searchParams) {
        SearchRequest request=new SearchRequest("item");
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        if(StringUtils.isNotBlank(searchParams.getKey())) {
            boolQuery.must(QueryBuilders.matchQuery("all", searchParams.getKey()));
        }
        if(StringUtils.isBlank(searchParams.getKey())){
            boolQuery.must(QueryBuilders.matchAllQuery());
        }
        //种类精确查询
        if(org.apache.commons.lang3.StringUtils.isNotBlank(searchParams.getCategory())){
            boolQuery.filter(QueryBuilders.termQuery("category",searchParams.getCategory()));
        }
        //品牌精确查询
        if(org.apache.commons.lang3.StringUtils.isNotBlank(searchParams.getBrand())){
            boolQuery.filter(QueryBuilders.termQuery("brand",searchParams.getBrand()));
        }
        //范围查询最低价格
        if(searchParams.getMinPrice()!=null){
            boolQuery.filter(QueryBuilders.rangeQuery("price").gte(searchParams.getMinPrice()));
        }
        //范围查询最低价格
        if(searchParams.getMaxPrice()!=null){
            boolQuery.filter(QueryBuilders.rangeQuery("price").lte(searchParams.getMaxPrice()));
        }
        //销量排序
        if("sold".equals(searchParams.getSortBy())){
            request.source().sort("sold", SortOrder.DESC);
        }
        //价格排序
        if("price".equals(searchParams.getSortBy())){
            request.source().sort("price",SortOrder.ASC);
        }
        request.source().query(boolQuery);
        Integer page = (searchParams.getPage()-1)*searchParams.getSize();
        request.source().from(page).size(searchParams.getSize());
        request.source().size(0);
        SearchVo searchVo = new SearchVo();
        request.source().aggregation(AggregationBuilders.terms("brandaggregation").field("brand"));
        request.source().aggregation(AggregationBuilders.terms("categoryaggregation").field("category"));
        try {
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            Set<String> brand = aggress(response, "brand");
            Set<String> category = aggress(response, "category");
            searchVo.setBrand(brand);
            searchVo.setCategory(category);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return searchVo;
    }
   @Autowired
   private RedisTemplate redisTemplate;
    @Autowired
    private RestHighLevelClient client;
    @Override
    public PageDTO getList(SearchParams searchParams) {
        if(searchParams.getKey()==null||searchParams.getKey()==""){
            List<Item> top20 = (List<Item>) redisTemplate.opsForValue().get("top20");
            PageDTO pageDTO=new PageDTO();
            pageDTO.setTotal(20L);
            pageDTO.setList(top20);
            return pageDTO;
        }
        /*String sortBy = searchParams.getSortBy();
        if("default".equals(sortBy)){
            sortBy="";
        }
        LambdaQueryWrapper<Item> queryWrapper = Wrappers.<Item>lambdaQuery()
                .between((searchParams.getMinPrice()!=null&&searchParams.getMaxPrice()!=null),Item::getPrice, searchParams.getMinPrice(), searchParams.getMaxPrice())
                .orderByDesc(StringUtils.isNotBlank(sortBy)&&sortBy.equals("price"),Item::getPrice)
                .orderByDesc(StringUtils.isNotBlank(sortBy)&&sortBy.equals("sold"),Item::getSold)
                .like(StringUtils.isNotBlank(searchParams.getCategory()),Item::getCategory,searchParams.getCategory())
                .like(StringUtils.isNotBlank(searchParams.getBrand()),Item::getBrand,searchParams.getBrand())
                .like(StringUtils.isNotBlank(searchParams.getKey()),Item::getName,searchParams.getKey());
        IPage page = new Page(searchParams.getPage(),searchParams.getSize());
        IPage page1 = itemMapper.selectPage(page, queryWrapper);
        PageDTO<Item> pageDTO = new PageDTO<>();
        pageDTO.setTotal(page1.getTotal());
        pageDTO.setList(page1.getRecords());*/
        SearchRequest request=new SearchRequest("item");
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        boolQuery.must(QueryBuilders.matchQuery("all",searchParams.getKey()));
        //种类精确查询
        if(org.apache.commons.lang3.StringUtils.isNotBlank(searchParams.getCategory())){
            boolQuery.filter(QueryBuilders.termQuery("category",searchParams.getCategory()));
        }
        //品牌精确查询
        if(org.apache.commons.lang3.StringUtils.isNotBlank(searchParams.getBrand())){
            boolQuery.filter(QueryBuilders.termQuery("brand",searchParams.getBrand()));
        }
        //范围查询最低价格
        if(searchParams.getMinPrice()!=null){
            boolQuery.filter(QueryBuilders.rangeQuery("price").gte(searchParams.getMinPrice()));
        }
        //范围查询最低价格
        if(searchParams.getMaxPrice()!=null){
            boolQuery.filter(QueryBuilders.rangeQuery("price").lte(searchParams.getMaxPrice()));
        }
        //销量排序
        if("sold".equals(searchParams.getSortBy())){
            request.source().sort("sold", SortOrder.DESC);
        }
        //价格排序
        if("price".equals(searchParams.getSortBy())){
            request.source().sort("price",SortOrder.ASC);
        }
        //高亮设置
        request.source().highlighter(new HighlightBuilder().field("name").preTags("<em>").postTags("</em>").requireFieldMatch(false));
        //算分查询 竞价
        FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(boolQuery, new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
                new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.termQuery("isComplated", true), //算分查询条件
                        ScoreFunctionBuilders.weightFactorFunction(10)) //权重

        });
        functionScoreQueryBuilder.boostMode(CombineFunction.SUM);
        request.source().query(functionScoreQueryBuilder);
        Integer page = (searchParams.getPage()-1)*searchParams.getSize();
        request.source().from(page).size(searchParams.getSize());
        try {
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            SearchHits hits = response.getHits();
            long total = hits.getTotalHits().value;
            SearchHit[] hitsHits = hits.getHits();
            PageDTO pageDTO = new PageDTO<>();
            List<ItemDoc> list = new ArrayList<>();
            pageDTO.setTotal(total);
            if(hitsHits!=null &&hitsHits.length>0){
                for (SearchHit hitsHit : hitsHits) {
                    String source = hitsHit.getSourceAsString();
                    ItemDoc itemDoc = JSON.parseObject(source, ItemDoc.class);
                    Map<String, HighlightField> highlightFields = hitsHit.getHighlightFields();
                    if(highlightFields!=null &&highlightFields.size()>0){
                        HighlightField field = highlightFields.get("name");
                        if (field != null) {
                            // 获取高亮值
                            String name = field.getFragments()[0].string();
                            itemDoc.setName(name);
                        }
                    }
                    list.add(itemDoc);
                }
                pageDTO.setList(list);
            }
            return pageDTO;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public List<Item> getTop20() {
        List<Item> list = itemMapper.getTop20();
        return list;
    }

    @Override
    public void decreamStock(Long itemId, Integer num) {
        Item item = itemMapper.selectById(itemId);
        if(item.getStock()<num){
            throw new RuntimeException("库存不足");
        }
        item.setStock(item.getStock()-num);
        item.setSold(item.getSold()+num);
        itemMapper.updateById(item);
    }

    @Override
    public void recoverStock(Long itemId, Integer num) {
        Item item = itemMapper.selectById(itemId);
        item.setStock(item.getStock()+num);
        item.setSold(item.getSold()-num);
        itemMapper.updateById(item);
    }

    public Set<String> aggress(SearchResponse response,String filed) throws IOException {
        Aggregations aggregations = response.getAggregations();
        Terms aggregation = aggregations.get(filed+"aggregation");
        List<? extends Terms.Bucket> buckets = aggregation.getBuckets();
        Set<String> setList =new HashSet<>();
        if(buckets!=null &&buckets.size()>0){
            for (Terms.Bucket bucket : buckets) {
                String key = bucket.getKeyAsString();
                setList.add(key);
            }
        }
        return setList;
    }
}
